import network.Device;
import network.Network;
import networkLoader.FabricNetwork;
import org.checkerframework.checker.units.qual.A;
import partition.AbstractNetwork;
import partition.Aggregator;
import partition.Partition;
import partition.LocalTask;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class PartitionTest {
    public static Network globalNetwork;
    public static HashMap<String, Partition> setupPartitionWithLTs() {
        Network network = FabricNetwork.getNetwork(112);
        globalNetwork = network;
        HashMap<String, Partition> nameToPartition = FabricNetwork.setupPartitions(network);
        String[] ptnames = {"pod-0", "pod-1", "spine-0-0"};
        HashSet<String> ptns = new HashSet<String>(Arrays.asList(ptnames));
        for (Partition partition : nameToPartition.values()) {
            String ptname = partition.getName();
            if (!ptns.contains(ptname)) {
//                continue;
            }
            if (ptname.startsWith("pod")) {
                String podId = ptname.split("-")[1];
                // inter pod up
                for (int iRsw = 0; iRsw < 48; iRsw++) {
                    for (int iFsw = 0; iFsw < 4; iFsw++) {
                        for (int iPort = 0; iPort < 48; iPort++) {
                            LocalTask localTask = new LocalTask(partition.getNetwork().getDevice("rsw-" + podId + "-" + iRsw),
                                    partition.getNetwork().getDevice("fsw-" + podId + "-" + iFsw).getPort("fsw-" + podId + "-" + iFsw + ">ssw-" + iFsw + "-" + iPort));
                            partition.addLocalTask(localTask);
                        }
                    }
                }
                // inter pod down
                for (int iFsw = 0; iFsw < 4; iFsw++) {
                    for (int iRsw = 0; iRsw < 48; iRsw++) {
                        LocalTask localTaskDown = new LocalTask(
                                partition.getNetwork().getDevice("fsw-" + podId + "-" + iFsw),
                                partition.getNetwork().getDevice("rsw-" + podId + "-" + iRsw).getPort("rsw-" + podId + "-" + iRsw + ">h-" + podId + "-" + iRsw));
                        partition.addLocalTask(localTaskDown);
                    }
                }
                // intra pod
                for (int iRsw = 0; iRsw < 48; iRsw++) {
                    for (int iRsw1 = 0; iRsw1 < 48; iRsw1++) {
                        if (iRsw != iRsw1) {
                            LocalTask localTask = new LocalTask(partition.getNetwork().getDevice("rsw-" + podId + "-" + iRsw),
                                    partition.getNetwork().getDevice("rsw-" + podId + "-" + iRsw1).getPort("rsw-" + podId + "-" + iRsw1 + ">h-" + podId + "-" + iRsw1));
                            partition.addLocalTask(localTask);
                        }
                    }
                }
            }
            if (ptname.startsWith("spine")) {
                for (Device device : partition.getNetwork().getAllDevices()) {
                    String iSpine = ptname.split("-")[1];
                    String iSsw = ptname.split("-")[2];
                    for (int iPod = 0; iPod < 112; iPod++) {
                        if (iPod != Integer.parseInt(iSsw)) {
                            LocalTask localTask = new LocalTask(device,
                                    device.getPort(device.getName() + ">fsw-" + iPod + "-" + iSpine));
                            partition.addLocalTask(localTask);
                        }
                    }
                }
            }

        }
        return nameToPartition;
    }

    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
        HashMap<String, Partition> nameToPartition = setupPartitionWithLTs();
        for (Partition partition : nameToPartition.values()) {
            long s = System.nanoTime();
            partition.test(1000);
            long end = System.nanoTime() - s;
            if (partition.getName().startsWith("p")) {
                System.out.println("#partition " + partition.getName() + " model update takes: " + end);
            }
//            partition.runLocalTasks();
        }
//        long s = System.nanoTime();
//        Aggregator aggregator = new Aggregator(nameToPartition);
//        aggregator.getNetworkModel();
//        System.out.println("aggr takes: " + (System.nanoTime() - s));
//        aggregator.allPairWithLTs();

//        long bddTT = 0;
//        long totalTT = 0;
//        long bddopTT = 0;
//        int transferCnt = 0;
//        for (int i = 0; i < 10; i++) {
//            Aggregator aggregator = new Aggregator(nameToPartition);
//            long s = System.nanoTime();
//            aggregator.checkReach();
//            bddTT += aggregator.bddTransferTime;
//            bddopTT += aggregator.bddOpTime;
//            totalTT += (System.nanoTime() - s);
//            transferCnt += aggregator.transferCnt;
//        }
//        System.out.println("total time: " + totalTT / 10000 + "us");
//        System.out.println("bdd transfer time: " + bddTT / 10000 + "us");
//        System.out.println("bdd transfer cnt: " + (transferCnt / 10));
//        System.out.println("bdd op time: " + bddopTT / 10000 + "us");
//        System.out.println("other time: " + (totalTT - bddTT - bddopTT) / 10000 + "us");

//        AbstractNetwork abstractNetwork = new AbstractNetwork(nameToPartition);
//        abstractNetwork.originNet = network;
//        long s = System.nanoTime();
////        abstractNetwork.aggr();
////        System.out.println(System.nanoTime() - s);
//        s = System.nanoTime();
//        abstractNetwork.allPairReach();
//        System.out.println("all pair check takes: " + (System.nanoTime() - s));

    }
}
